package avicit.bdp.dds.api.controller;

import avicit.bdp.common.dto.query.dds.ExecutorQuery;
import avicit.bdp.dds.dispatch.enums.CommandType;
import avicit.bdp.dds.dispatch.enums.ExecutionStatus;
import avicit.bdp.dds.dispatch.enums.FailureStrategy;
import avicit.bdp.dds.dispatch.enums.Priority;
import avicit.bdp.dds.dispatch.enums.RunMode;
import avicit.bdp.dds.dispatch.enums.TaskDependType;
import avicit.bdp.dds.dispatch.enums.WarningType;
import avicit.bdp.dds.dao.entity.ProcessDefinition;
import avicit.bdp.dds.dao.entity.ProcessInstance;
import avicit.bdp.dds.dao.entity.TaskInstance;
import avicit.bdp.dds.dao.mapper.ProcessDefinitionMapper;
import avicit.bdp.dds.dao.mapper.ProcessInstanceMapper;
import avicit.bdp.dds.server.master.MasterServer;
import avicit.platform6.core.rest.msg.QueryRespBean;
import avicit.platform6.core.rest.msg.ResponseMsg;
import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.Page;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;
import java.util.Map;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2020-06-24 14:54
 * @类说明：ProcessDefinitionRest
 * @修改记录：
 * @注意事项：
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProcessInstanceRestTest {
    @Autowired
    ProcessInstanceRest processInstanceRest;

    @Autowired
    ExecutorRest executorRest;

    @Autowired
    ProcessDefinitionRest processDefinitionRest;

    @Autowired
    ProcessDefinitionMapper processDefinitionMapper;

    @Autowired
    private ProcessInstanceMapper processInstanceMapper;

    private static ProcessDefinition processDefeCreate;

    /**
     * 所有用例执行前准备工作
     */
    @BeforeClass
    public static void init() {
        // step1:构造流程定义参数;
        String processDefeStrCreate = "{\n" +
                "    \"id\": \"d48644cc-2c7a-4714-9900-18ab99e80b77\",\n" +
                "    \"name\": \"datax_job\",\n" +
                "    \"releaseState\": \"ONLINE\",\n" +
                "    \"projectId\": 456,\n" +
                "\t\"typeId\": \"datax\",\n" +
                "\t\"type\": 0,\n" +
                "\t\"remark\": \"测试任务1\",\n" +
                "\t\"datasourceId\": 1,\n" +
                "\t\"processDefinitionJson\": \"{\\\"globalParams\\\":[],\\\"tasks\\\":[{\\\"type\\\":\\\"DATAX\\\",\\\"id\\\":\\\"tasks-24986\\\",\\\"name\\\":\\\"test\\\",\\\"params\\\":{\\\"customConfig\\\":0,\\\"dsType\\\":\\\"MYSQL\\\",\\\"dataSource\\\":1,\\\"dtType\\\":\\\"MYSQL\\\",\\\"dataTarget\\\":1,\\\"sql\\\":\\\"select * from db1;\\\",\\\"targetTable\\\":\\\"db2\\\",\\\"jobSpeedByte\\\":0,\\\"jobSpeedRecord\\\":1000,\\\"preStatements\\\":[],\\\"postStatements\\\":[]},\\\"description\\\":\\\"\\\",\\\"runFlag\\\":\\\"NORMAL\\\",\\\"conditionResult\\\":{\\\"successNode\\\":[\\\"\\\"],\\\"failedNode\\\":[\\\"\\\"]},\\\"dependence\\\":{},\\\"maxRetryTimes\\\":\\\"0\\\",\\\"retryInterval\\\":\\\"1\\\",\\\"timeout\\\":{\\\"strategy\\\":\\\"\\\",\\\"interval\\\":null,\\\"enable\\\":false},\\\"taskInstancePriority\\\":\\\"MEDIUM\\\",\\\"workerGroup\\\":\\\"default\\\",\\\"preTasks\\\":[]}],\\\"tenantId\\\":1,\\\"timeout\\\":0}\",\n" +
                "\t\"locations\": \"{\\\"tasks-34878\\\":{\\\"name\\\":\\\"datax自定义模板测试\\\",\\\"targetarr\\\":\\\"\\\",\\\"nodenumber\\\":\\\"0\\\",\\\"x\\\":424,\\\"y\\\":312}}\",\n" +
                "\t\"createdBy\": \"dcs\",\n" +
                "\t\"createdDate\": \"2020-08-04 11:23:17\",\n" +
                "\t\"lastUpdatedBy\":\"dcs\",\n" +
                "\t\"lastUpdateDate\": \"2020-08-04 11:23:17\"\n" +
                "}";
        processDefeCreate = JSON.parseObject(processDefeStrCreate, ProcessDefinition.class);
        processDefeCreate.setProjectId("828081857409c289017409c289801111");

        // step2:启动master进程；（定期拉去CMD表，生成processInstance）
        String[] args = new String[0];
        MasterServer.main(args);
    }

    /**
     * 单个测试用例运行前准备工作
     */
    @Before
    public void setUp() {
        // TODO:
    }

    /**
     * 单个测试用例运行后销毁工作
     */
    @After
    public void tearDown() {
        // TODO:
    }

    /**
     * 所有用例执行完成后准备工作
     */
    @AfterClass
    public static void destory() {
        // TODO:
    }

    /**
     * 预先创建流程定义；
     * @throws RuntimeException
     */
    public void createProcessDefe() throws RuntimeException{
        try {
            ResponseMsg<String> responseMsg = processDefinitionRest.createProcessDefinition(processDefeCreate);
            if (!"200".equals(responseMsg.getRetCode())) {
                System.out.println("Create processDefe failed.");
                throw new RuntimeException("Create processDefe failed.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 预先上线流程定义；
     * @throws RuntimeException
     */
    public void releaseProcessDefe(int releaseState) throws RuntimeException{
        try {
            ResponseMsg<Boolean> responseMsg =
                    processDefinitionRest.releaseProcessDefinition(processDefeCreate.getId(), releaseState);

            if (!"200".equals(responseMsg.getRetCode())) {
                System.out.println("Release processDefe failed.");
                throw new RuntimeException("Release processDefe failed.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 启动流程定义；
     */
    public void startProcIns() throws Exception {
        String processDefinitionId = processDefeCreate.getId();
        String scheduleTime = "";
        FailureStrategy failureStrategy = FailureStrategy.CONTINUE;
        String startNodeList = null;
        TaskDependType taskDependType = TaskDependType.TASK_POST;
        CommandType execType = CommandType.START_CURRENT_TASK_PROCESS;
        WarningType warningType = WarningType.FAILURE;
        String warningUserIds = "avicit2015";
        RunMode runMode = RunMode.RUN_MODE_SERIAL;
        Priority processInstancePriority = Priority.MEDIUM;
        String workerGroup = null;
        Integer timeout = null;

        ExecutorQuery executorQuery = new ExecutorQuery();
        // todo set value

        ResponseMsg<Boolean> responseMsg = executorRest.startProcessInstance(executorQuery);

        Assert.assertEquals("200",responseMsg.getRetCode());
    }

    /**
     * 用例执行完毕后删除流程定义；
     * @throws RuntimeException
     */
    public void deleteProcessDefe() throws RuntimeException{
        try {
            ResponseMsg<Boolean> responseMsg = processDefinitionRest.deleteProcessDefinitionById(processDefeCreate.getId());
            if (!"200".equals(responseMsg.getRetCode())) {
                System.out.println("Delete processDefe failed.");
                throw new RuntimeException("Delete processDefe failed.");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 用例执行完后删除流程实例；
     * @throws RuntimeException
     */
    public void deleteProcessInstance() throws RuntimeException{
        try {
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }

            for (ProcessInstance processInstance : processInstances) {
                int ret = processInstanceMapper.deleteByPrimaryKey(processInstance.getId());
                if (ret <= 0) {
                    throw new RuntimeException("Delete processInstance " + processInstance.getId() + " failed.");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /***************************************************************
     ******************       正常场景测试用例       ******************
     ***************************************************************/
    /**
     * 分页查询流程实例列表；
     * @throws Exception
     */
    @Test
    public void testQueryProcessInstanceList_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义；
            createProcessDefe();
            releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待2s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }

            // step2:执行阶段
            String processDefinitionId = processDefeCreate.getId();
            String searchVal = null;
            String host = null;
            String startTime = null;
            String endTime = null;
            Integer pageNo = 1;
            Integer pageSize = 10;
            ResponseMsg<QueryRespBean<ProcessInstance>> respBeanResponseMsg =
                    processInstanceRest.queryProcessInstanceList(processDefinitionId, searchVal,
                            ExecutionStatus.RUNNING_EXEUTION, host, startTime, endTime, pageNo, pageSize);

            // step3:验证阶段：（1）验证分页查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",respBeanResponseMsg.getRetCode());
            QueryRespBean<ProcessInstance> queryRespBean = respBeanResponseMsg.getResponseBody();
            Page<ProcessInstance> processInstancePage = queryRespBean.getResult();
            List<ProcessInstance> processInstanceList = processInstancePage.getResult();
            Assert.assertEquals(processInstanceList.size() >= 1, true);
        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例（3）删除流程实例
            releaseProcessDefe(0);
            deleteProcessInstance();
            deleteProcessDefe();
        }
    }

    /**
     * 根据流程实例ID查询列表；
     * @throws Exception
     */
    @Test
    public void testQueryTaskListByProcessId_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义；
            createProcessDefe();
            releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待2s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }

            // step2:执行阶段
            ResponseMsg<List<TaskInstance>> responseMsg = processInstanceRest.queryTaskListByProcessId(
                    processInstances.get(0).getId());

            // step3:验证阶段：（1）验证查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",responseMsg.getRetCode());
            List<TaskInstance> taskInstanceList = responseMsg.getResponseBody();

            // TODO:task打通之后再判断
            Assert.assertEquals(taskInstanceList.size() == 0, true);
        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例（3）删除流程实例
            releaseProcessDefe(0);
            deleteProcessInstance();
            deleteProcessDefe();
        }
    }

    /**
     * 更新流程实例；
     * @throws Exception
     */
    @Test
    public void testUpdateProcessInstance_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义（4）查询流程实例（5）设置流程实例状态为已完成（6）准备更新流程实例参数
            // step1_1:创建流程定义、发布流程定义;
            createProcessDefe();
            releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待2s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }
            ProcessInstance processInstance = processInstances.get(0);

            // step1_3:设置流程实例状态为已完成；（只有处于Success/Pause/Stop等状态的流程实例才允许修改）
            processInstance.setState(ExecutionStatus.SUCCESS.getCode());
            int ret = processInstanceMapper.updateByPrimaryKey(processInstance);
            Assert.assertEquals(ret > 0, true);

            // step1_4:准备更新流程实例API接口参数；
            String projectName = processDefeCreate.getProjectName();
            String processInstanceJson = "{\"globalParams\":[],\"tasks\":[{\"type\":\"DATAX\",\"id\":\"tasks-24986\"," +
                    "\"name\":\"test\",\"params\":{\"customConfig\":0,\"dsType\":\"MYSQL\",\"dataSource\":2,\"dtType\":\"MYSQL\"," +
                    "\"dataTarget\":2,\"sql\":\"select * from db1;\",\"targetTable\":\"db2\",\"jobSpeedByte\":0," +
                    "\"jobSpeedRecord\":1000,\"preStatements\":[],\"postStatements\":[]},\"description\":\"\",\"runFlag\":\"NORMAL\"," +
                    "\"conditionResult\":{\"successNode\":[\"\"],\"failedNode\":[\"\"]},\"dependence\":{},\"maxRetryTimes\":\"0\"," +
                    "\"retryInterval\":\"1\",\"timeout\":{\"strategy\":\"\",\"interval\":null,\"enable\":false},\"taskInstancePriority\":\"MEDIUM\"," +
                    "\"workerGroup\":\"default\",\"preTasks\":[]}],\"tenantId\":1,\"timeout\":0}";
            String processInstanceId = processInstance.getId();
            String scheduleTime = null;
            Boolean syncDefine = true;
            String locations = null;
            String connects = null;

            // step2:执行阶段
            ResponseMsg responseMsg = processInstanceRest.updateProcessInstance(projectName, processInstanceJson, processInstanceId,
                    scheduleTime, syncDefine, locations, connects);

            // step3:验证阶段：（1）验证查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",responseMsg.getRetCode());
        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例（3）删除流程实例
            releaseProcessDefe(0);
            deleteProcessInstance();
            deleteProcessDefe();
        }
    }

    /**
     * 根据流程实例ID查询
     */
    @Test
    public void testQueryProcessInstanceById_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义（4）查询流程实例
            // step1_1:创建流程定义、发布流程定义;
            createProcessDefe();
            releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();

            // step1_3:查询流程实例
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待2s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }
            ProcessInstance processInstance = processInstances.get(0);

            // step2:执行阶段
            ResponseMsg<ProcessInstance> responseMsg = processInstanceRest.queryProcessInstanceById(null, processInstance.getId());

            // step3:验证阶段：（1）验证查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",responseMsg.getRetCode());
            ProcessInstance rsp = responseMsg.getResponseBody();
            Assert.assertEquals(rsp.getName().equals(processInstance.getName()), true);
        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例（3）删除流程实例
            releaseProcessDefe(0);
            deleteProcessInstance();
            deleteProcessDefe();
        }
    }

    /**
     * 根据流程实例ID删除
     */
    @Test
    public void testDeleteProcessInstanceById_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义（4）查询流程实例
            // step1_1:创建流程定义、发布流程定义;
            createProcessDefe();
            releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();

            // step1_3:查询流程实例
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待2s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }
            ProcessInstance processInstance = processInstances.get(0);

            // step2:执行阶段
            ResponseMsg responseMsg = processInstanceRest.deleteProcessInstanceById(processInstance.getId());

            // step3:验证阶段：（1）验证查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",responseMsg.getRetCode());
        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例
            releaseProcessDefe(0);
            deleteProcessDefe();
        }
    }

    /**
     * 根据TaskId查询子流程实例；
     */
    @Test
    public void testQuerySubProcessInstanceByTaskId_1() throws Exception {
        // TODO:
    }

    /**
     * 根据subId子流程实例ID查询父流程实例
     */
    @Test
    public void testQueryParentInstanceBySubId_1() throws Exception {
        // TODO:
    }

    /**
     * 根据流程实例ID查询参数
     */
    @Test
    public void testViewVariables_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义（4）查询流程实例
            // step1_1:创建流程定义、发布流程定义;
            createProcessDefe();
            releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();

            // step1_3:查询流程实例
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待2s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }
            ProcessInstance processInstance = processInstances.get(0);

            // step2:执行阶段
            ResponseMsg<Map<String, Object>> responseMsg = processInstanceRest.viewVariables(processInstance.getId());

            // step3:验证阶段：（1）验证查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",responseMsg.getRetCode());
        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例
            releaseProcessDefe(0);
            deleteProcessDefe();
        }
    }

    /**
     * 批量删除流程实例；
     */
    @Test
    public void testBatchDeleteProcessInstanceByIds_1() throws Exception {
        try {
            // step1:准备阶段:（1）创建流程定义（2）发布流程定义（3）启动流程定义（4）查询流程实例
            // step1_1:创建流程定义、发布流程定义;
            createProcessDefe();
            releaseProcessDefe(1);

            // step1_2:启动流程定义；
            startProcIns();

            // step1_3:查询流程实例
            // MasterSchedulerService线程每隔1s扫描一次CMD，此处等待2s，保证ProcessInstance被创建；
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            List<ProcessInstance> processInstances = processInstanceMapper.queryByProcessDefineId(processDefeCreate.getId(), 1);
            if (processInstances == null || processInstances.size() <= 0) {
                Assert.assertEquals(true, false);
            }
            String processInstanceIds = processInstances.get(0).getId();

            // step2:执行阶段
            ResponseMsg responseMsg = processInstanceRest.deleteProcessInstanceById(processInstanceIds);

            // step3:验证阶段：（1）验证查询流程实例执行结果（2）验证流程实例数据；
            Assert.assertEquals("200",responseMsg.getRetCode());
        } finally {
            // step4:清理阶段；（1）删除流程定义（2）下线流程实例
            releaseProcessDefe(0);
            deleteProcessDefe();
        }
    }

    /***************************************************************
     ******************       异常场景测试用例       ******************
     ***************************************************************/

}
